package com.axialproject.health.exchange;

import com.axialproject.health.exchange.entity.Gender;
import com.axialproject.health.exchange.entity.Patient;
import com.axialproject.health.exchange.entity.Race;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class ConnectorListener extends HttpServlet {

    private static final Logger log = Logger.getLogger(ConnectorListener.class.getName());

    public void doPost (HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        Record record = getRecord (req);
        if (record == null) {
            record = getDefaultRecord (req);
        }

        Patient patient = getPatient (req);
        if (patient == null) {
            patient = getDefaultPatient (req);
        }
        String password = req.getParameter("password");
        if (password == null || !password.equals(patient.getPassword())) {
            log.severe("The password does not match for patient " + patient.getId());
            throw new ServletException ("The password does not match!");
        }

        String [] destinations = getDestinations (req);

        for (String destination : destinations) {
            try {
                Router router = (Router) Class.forName("com.axialproject.health.exchange." + destination + ".RouterImpl").newInstance();
                router.sendRecord(patient, record);
            } catch (Exception e) {
                log.log(Level.SEVERE, e.getMessage(), e);
            }
        }
        
        // Generate a 200 response
        resp.setContentType("text/plain");
        resp.getWriter().print("");
    }

    public void doGet (HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        doPost (req, resp);
    }

    protected List <String> parseInputParameter (String param) {
        ArrayList <String> result = new ArrayList <String> ();
        StringTokenizer st = new StringTokenizer(param, "|");
        while (st.hasMoreTokens()) {
            result.add (st.nextToken().trim());
        }
        return result;
    }

    abstract protected String getAppName ();
    abstract protected Record getRecord (HttpServletRequest req);
    abstract protected Patient getPatient (HttpServletRequest req);
    abstract protected String [] getDestinations (HttpServletRequest req);


    protected Record getDefaultRecord (HttpServletRequest req) {
        Record record = new Record ();
        record.setTitle(req.getParameter("title"));
        record.setType(req.getParameter("type"));
        record.setDescription(req.getParameter("description"));

        Date start = new Date();
        try {
            long startDate = Long.parseLong(req.getParameter("start"));
            start = new Date (startDate);
        } catch (Exception e) {
            // There is no "start" param. We will just use today
            log.info ("Cannot parse start param " + e.getMessage());
        }

        Calendar cal = Calendar.getInstance();
        cal.setTime(start);
        cal.add(Calendar.DAY_OF_YEAR, 1);
        Date tomorrow = cal.getTime();

        record.setStart(start);
        record.setStop(tomorrow);

        String [] allergies = req.getParameterValues("allergies");
        if (allergies == null) {
            allergies = new String [0];
        }
        ArrayList <String> allergens = new ArrayList <String> ();
        ArrayList <String> severities = new ArrayList <String> ();
        for (String allergy : allergies) {
            List <String> comps = parseInputParameter (allergy);
            allergens.add (comps.get(0));
            severities.add (comps.get(1));
        }
        record.setAllergyAllergens(allergens);
        record.setAllergySeverities(severities);

        String [] testresults = req.getParameterValues("testresults");
        if (testresults == null) {
            testresults = new String [0];
        }
        ArrayList <String> testNames = new ArrayList <String> ();
        ArrayList <String> testResults = new ArrayList <String> ();
        ArrayList <String> testResultUnits = new ArrayList <String> ();
        ArrayList <String> testResultNormalRanges = new ArrayList <String> ();
        for (String testresult : testresults) {
            List <String> comps = parseInputParameter (testresult);
            testNames.add (comps.get(0));
            testResults.add (comps.get(1));
            testResultUnits.add (comps.get(2));
            testResultNormalRanges.add (comps.get(3));
        }
        record.setTestNames(testNames);
        record.setTestResults(testResults);
        record.setTestResultUnits(testResultUnits);
        record.setTestResultNormalRanges(testResultNormalRanges);

        String [] ms = req.getParameterValues("medications");
        if (ms == null) {
            ms = new String [0];
        }
        ArrayList <String> medications = new ArrayList <String> ();
        ArrayList <String> medicationDoses = new ArrayList <String> ();
        ArrayList <String> medicationDoseUnits = new ArrayList <String> ();
        for (String m : ms) {
            List <String> comps = parseInputParameter (m);
            medications.add (comps.get(0));
            medicationDoses.add (comps.get(1));
            medicationDoseUnits.add (comps.get(2));
        }
        record.setMedications (medications);
        record.setMedicationDoses (medicationDoses);
        record.setMedicationDoseUnits (medicationDoseUnits);

        String [] cs = req.getParameterValues("conditions");
        if (cs == null) {
            cs = new String [0];
        }
        ArrayList <String> conditions = new ArrayList <String> ();
        for (String c : cs) {
            List <String> comps = parseInputParameter (c);
            conditions.add (comps.get(0));
        }
        record.setConditions (conditions);

        record.setDoctorName(req.getParameter("doctorName"));
        record.setDoctorTitle(req.getParameter("doctorTitle"));

        return record;
    }

    protected Patient getDefaultPatient(HttpServletRequest req) throws ServletException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        Patient patient = null;
        EntityManager em = EMF.get().createEntityManager();
        try {
            patient = PatientManager.getPatientByUsernameAppName(em, username, getAppName());
        } catch (Exception e) {
            log.log (Level.SEVERE, e.getMessage(), e);
        } finally {
            em.close ();
        }

        if (password == null || !password.equals(patient.getPassword())) {
            log.severe("The password is wrong for user " + patient.getId());
            throw new ServletException ("The password is wrong.");
        }
        return patient;
    }

}
